<html>
<head>
<title>CpcPaChi - Version 0.18</title>
<style type="text/css">
span {
	font-family: 'Courier New';
	font-size: 10pt;
	color: #000000;
}
.sc0 {
	color: #808080;
}
.sc3 {
	color: #008080;
}
.sc4 {
	color: #FF8000;
}
.sc5 {
	font-weight: bold;
	color: #0000FF;
}
.sc7 {
	color: #808080;
}
.sc9 {
	color: #804000;
}
.sc10 {
	font-weight: bold;
	color: #000080;
}
.sc11 {
}
</style>
</head>
<body>
<h2>Un compilador sencillo paso a paso (18 - Varios tipos de datos)</h2>

<p align="right">(Volver al <a href="doc.html">&iacute;ndice</a>) </p>

<p>Nuestro compilador permite un &uacute;nico tipo de datos: &quot;byte&quot;, un n&uacute;mero entero con valores desde 0 hasta 255. Para programas sencillos puede ser suficiente, pero cualquier programa real necesitar&aacute; m&aacute;s. De momento esquivaremos los n&uacute;meros reales, que son mucho m&aacute;s lentos de manipular que los enteros, pero deber&iacute;amos al menos a&ntilde;adir un tipo de datos &quot;integer&quot;, un n&uacute;mero entero de 2 bytes, que nos permita acceder a coordenadas de pantalla para nuestros programas en modo gr&aacute;fico.</p>

<p>Adem&aacute;s, as&iacute; esto supondr&aacute; un acercamiento a los problemas de an&aacute;lisis sem&aacute;ntico: ver si en cada contexto se est&aacute; usando el tipo de datos correcto.</p>

<p>Por ejemplo, vamos a comentar algunos casos de asignaciones, pero habr&iacute;a problemas similares cuando se llamara a funciones que esperan par&aacute;metros de esos tipos:</p>

<pre><code>var i1, i2: integer;
var b1, b2: byte;

i1 := 2;   (* Correcto *)
i2 := 300; (* Correcto *)
b1 := 3;   (* Correcto *)
b2 := 400; (* Incorrecto: valor fuera de rango *)
i1 := i2;  (* Correcto *)
i1 := b2;  (* Correcto, pero hay que ampliar el rango del numero *)
b1 := i1;  (* Incorrecto, posible valor fuera de rango *)
</code></pre>

<p>Lo de &quot;ampliar el rango del n&uacute;mero&quot; en el caso de &quot;i1 := b2&quot; se refiere a que no basta con copiar el contenido de la direcci&oacute;n de memoria de b2 a la direcci&oacute;n de memoria de i1, porque tienen tama&ntilde;os distintos: si copiamos s&oacute;lo el &uacute;nico byte de b2, dejaremos un byte de i1 con basura, y el valor final puede ser incorrecto; si leemos 2 bytes de la direcci&oacute;n de b2, tomaremos un dato que no pertenece a b2, y nuevamente podemos obtener un resultado incorrecto. Deberemos copiar b2 en el byte bajo de i1 y dejar a cero el byte alto de i1.</p>

<p>Los pasos que daremos ser&aacute;n:</p>
<ul>
  <li>El analizador sint&aacute;ctico tendr&aacute; que reconocer el tipo &quot;integer&quot; dentro de las declaraciones &quot;var&quot;: lo que antes era</li>
</ul>

<blockquote>
  <p><pre><code>if (tipoVar &lt;&gt; 'BYTE') then
 &nbsp;errorFatal('Tipo incorrecto');
insertarSimboloVar(ident, tByte);</code></pre></p>

  <p>ahora se convertir&aacute; en</p>
  
  <p><pre><code>if (tipoVar = 'BYTE') then
  insertarSimboloVar(ident, tByte)
else if (tipoVar = 'INTEGER') then
  insertarSimboloVar(ident, tInteger)
else errorFatal('Tipo incorrecto');</code></pre></p>
</blockquote>

<ul>
  <li>Las &oacute;rdenes de CPC que deben recibir par&aacute;metros de tipo byte, deber&aacute;n ahora comprobar que el dato recibido es de ese tipo:</li>
</ul>

<blockquote>
  <p><pre><code>procedure analizarCPCMODE;
begin
  leerSimbolo('(');
  genLecturaValor(obtenerToken.valor);
  leerSimbolo(')');
  leerSimbolo(';');
  genCPCMODE;
end;</code></pre></p>

  <p>ahora se convertir&aacute; en</p>
  
  <p><pre><code>procedure analizarCPCMODE;
var
  t: token;
begin
  leerSimbolo('(');
  t := obtenerToken;
  if not validarByte(t) then errorFatal('Se esperaba un dato de tipo byte');  
  genLecturaValor(t.valor);
  leerSimbolo(')');
  leerSimbolo(';');
  genCPCMODE;
end;
</code></pre></p>

  <p>donde la funci&oacute;n &quot;validarByte&quot; comprobar&aacute; si es una n&uacute;mero cuyo rango entre dentro de los &quot;byte&quot;, o un elemento de tabla de s&iacute;mbolos que tenga ese tipo de datos:</p>
  
<p><pre><code>function validarByte(t: token): boolean;
var
  valorInt, codError: integer;
  tipoDato: byte;
  valido: boolean;
begin
  valido := true;
  if (t.tipo = tkENTERO) then
    begin
    val(t.valor, valorInt, codError);
    if (valorInt &lt; 0) or (valorInt &gt; 255) or (codError &lt;&gt; 0) then      
      valido := false;
    end;  
  if (t.tipo &lt;&gt; tkENTERO) then
    begin
    tipoDato := leerTipoDatoTS(t.valor);
    if tipoDato &lt;&gt; tByte then      
      valido := false;
    end;  
  validarByte := valido;
end;
</code></pre></p>
  
</blockquote>

<ul>
  <li>Las funciones que pueden trabajar tanto con datos &quot;byte&quot; como &quot;integer&quot; deber&aacute;n comprobar el tipo de dato del que se trata, como por ejemplo DEC:</li>
</ul>

<blockquote>
  <pre><code>procedure genDEC(nombre: string; decremento: integer);<br>begin<br>  if validarByteNombre(nombre) and (decremento&gt;0) and (decremento&lt;255) then<br>    genDECbyte(nombre, decremento)<br>  else<br>    genDECinteger(nombre, decremento);<br>end;<br></code></pre>
  ahora DECbyte y DEC integer comprobar&aacute;n que realmente sea una variable (no tiene sentido decrementar una constante ni una funci&oacute;n) y mirar&aacute; de qu&eacute; tipo de dato se trata, para generar c&oacute;digo distinto seg&uacute;n sea un dato de 1 byte (y entonces se apoyar&aacute; en el registro A) o de 2 bytes (integer, que se apoyar&aacute; en HL). Por ejemplo, para el bye ahora ser&aacute;:<pre><code>procedure genDECbyte(nombre: string; decremento: byte);<br>var<br>  direccion: integer;<br>  i: byte;<br>begin<br>  (* Posiblemente seria mas razonable usar INC (HL) -34h*)  <br>  direccion := leerSimboloVar(nombre);<br>  genCodigo(3, '3A', hexStr(direccion mod 256,2),<br>    hexStr(direccion div 256,2),<br>    'LD A, (Variable '+nombre+')');<br>  <br>  (* Seria mas eficiente usar SUB si el valor es grande ## *)<br>  for i:=1 to decremento do<br>    begin<br>    genCodigo(1, '3D', '', '' ,' DEC A' );<br>    end;<br>  <br>  genCodigo(3, '32', hexStr(direccion mod 256,2),<br>    hexStr(direccion div 256,2),<br>    'LD ('+nombre+'), A');<br>end;</code></pre>
  
  </p>
</blockquote>



<p>De paso, crearemos un par de &oacute;rdenes que nos permitan empezar a dibujar en pantalla: PLOT (dibujar punto en ciertas coordenadas) y LINE (dibujar l&iacute;nea hasta otras coordenadas dadas), junto con una GRAPHICSPEN que nos permita cambiar el color en modo gr&aacute;fico. PLOT y LINE esperar&aacute;n par&aacute;metros de tipo INTEGER, pero ah&iacute; encontramos un riesgo: &iquest;que ocurre si hacemos PLOT(x,y) donde X e Y sean variables de tipo BYTE?&nbsp; Deberemos comprobar el tipo del dato que se recibe: si es un BYTE no debemos leer 2 bytes de memoria como si fuera un INTEGER, sino leer un &uacute;nico byte y ampliar el rango a 2 bytes antes de utilizar el valor. </p>
<p>&nbsp;</p>
<blockquote>
  <pre><code>procedure genPLOT(x, y: string);<br>begin<br>  genLectura2Integer(x, y);<br>  genCodigo(3, 'CD', 'EA', 'BB', 'CALL &amp;BBEA - PLOT ABSOLUTE' );<br>end;</code></pre><br>
Y parte de la lectura de cada uno de esos INTEGER es as&iacute;: comprobando si es de tipo byte, y en ese caso, se guarda en el registo A y luego se pasa a HL:

<pre><code>if tipoDato = tBYTE then<br>   begin<br>   genCodigo(3, '3A', hexStr(direccion mod 256,2),<br>     hexStr(direccion div 256,2), <br>     'LD A, (Variable '+nombre+')');<br>   genCodigo(3, '6F', '26', '00', ' A-&gt;HL: LD L, A - LD H, 0' );<br>   end
</code></pre>
</blockquote>

<p>Finalmente, aprovecharemos la ocasi&oacute;n para ampliar un poco la sintaxis de INC y DEC para que permitan auemntar el valor en m&aacute;s de una unidad: hacer tanto INC(X) como INC(X,3), algo que ya permit&iacute;a el generador de c&oacute;digo pero todav&iacute;a no el analizador sint&aacute;ctico..</p>
<p><br />
  Como siempre, para m&aacute;s detalles, todo el c&oacute;digo est&aacute; en la p&aacute;gina del proyecto en Google Code:<br />
  <br />
<a href="http://code.google.com/p/cpcpachi/">http://code.google.com/p/cpcpachi/</a></p>

<p align="right">(Volver al <a href="doc.html">&iacute;ndice</a>) </p>
</body>
</html>
